package com.fang.excel.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.fang.excel.entity.UserInformation;
import com.fang.excel.service.AsyncImportService;
import com.fang.excel.service.UserInformationService;
import com.quanzhi.openapi.host.HostRequired;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@RestController
@RequestMapping("/test")
public class ImportDataController {

    @Autowired
    private UserInformationService userInformationService;

    @Autowired
    private AsyncImportService asyncImportService;

    private static final int BATCH_SIZE = 20000;

    private static final String UPLOAD_DIR = "F:\\文档\\quanzhicode\\easy-excel-project1\\uploads";

    /**
     * 基础版本
     * @param file
     * @return
     */
    @PostMapping("/import1")
    public String importExcel1(@RequestParam("file") MultipartFile file) {
        Instant start = Instant.now();

        try {
            List<UserInformation> allData = new ArrayList<>();

            Instant start2 = Instant.now();
            EasyExcel.read(file.getInputStream(), UserInformation.class, new PageReadListener<UserInformation>(dataList -> {
                allData.addAll(dataList);
            })).sheet().doRead();
            Instant end2 = Instant.now();
            Duration timeElapsed1 = Duration.between(start2, end2);
            log.info("加载内存耗时："+timeElapsed1.toMillis());

            // 对数组进行分割
            List<List<UserInformation>> partitions = partitionList(allData, BATCH_SIZE);

            for (List<UserInformation> partition : partitions) {
                Instant start1 = Instant.now();
                userInformationService.saveBatch(partition);
                Instant end1 = Instant.now();
                Duration timeElapsed2 = Duration.between(start1, end1);
                log.info("插入耗时"+timeElapsed2.toMillis());
            }

            allData.clear();
        } catch (IOException e) {
            Instant end = Instant.now();
            Duration timeElapsed = Duration.between(start, end);
            return "导入失败: " + e.getMessage() + ". 时间消耗: " + timeElapsed.toMillis() + " 毫秒.";
        }

        Instant end = Instant.now();
        Duration timeElapsed = Duration.between(start, end);
        return "导入成功. 时间消耗: " + timeElapsed.toMillis() + " 毫秒.";
    }



    /**
     * 线程池版本
     * @param file
     * @return
     */
    @PostMapping("/import2")
    public String importExcel2(@RequestParam("file") MultipartFile file) {
        Instant start = Instant.now();
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

        try {
            Instant start2 = Instant.now();
            List<UserInformation> allData = new ArrayList<>();
            EasyExcel.read(file.getInputStream(), UserInformation.class, new PageReadListener<UserInformation>(dataList -> {
                allData.addAll(dataList);
            })).sheet().doRead();
            Instant end2 = Instant.now();
            Duration timeElapsed1 = Duration.between(start2, end2);
            log.info("加载内存耗时："+timeElapsed1.toMillis());

            // 对数组进行分割
            List<List<UserInformation>> partitions = partitionList(allData, BATCH_SIZE);

            // 提交至线程池处理
            for (List<UserInformation> partition : partitions) {
                executorService.submit(() -> userInformationService.saveBatch(partition));
            }

            executorService.shutdown();
            while (!executorService.isTerminated()) {
                // 等待所有线程完成
            }
        } catch (IOException e) {
            Instant end = Instant.now();
            Duration timeElapsed = Duration.between(start, end);
            return "导入失败: " + e.getMessage() + ". 时间消耗: " + timeElapsed.toMillis() + " 毫秒.";
        }

        Instant end = Instant.now();
        Duration timeElapsed = Duration.between(start, end);
        return "导入成功. 时间消耗: " + timeElapsed.toMillis() + " 毫秒.";
    }



    /**
     * 线程池版本+真批量插入
     * @param file
     * @return
     */
    @HostRequired
    @PostMapping("/import3")
    public String importExcel3(@RequestParam("file") MultipartFile file) {
        Instant start = Instant.now();
        List<UserInformation> allData = new ArrayList<>();

        try {
            EasyExcel.read(file.getInputStream(), UserInformation.class, new PageReadListener<UserInformation>(dataList ->{
                allData.addAll(dataList);
            })).sheet().doRead();

            // 调用异步方法处理数据导入
            asyncImportService.importData(allData);
            allData.clear();
        } catch (IOException e) {
            Instant end = Instant.now();
            Duration timeElapsed = Duration.between(start, end);
            return "导入失败: " + e.getMessage() + ". 时间消耗: " + timeElapsed.toMillis() + " 毫秒.";
        }

        Instant end = Instant.now();
        Duration timeElapsed = Duration.between(start, end);
        return "导入请求已接受. 时间消耗: " + timeElapsed.toMillis() + " 毫秒. 数据导入将在后台进行.";
    }

    private <T> List<List<T>> partitionList(List<T> list, int size) {
        List<List<T>> partitions = new ArrayList<>();
        for (int i = 0; i < list.size(); i += size) {
            partitions.add(new ArrayList<>(list.subList(i, Math.min(i + size, list.size()))));
        }
        return partitions;
    }

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return new ResponseEntity<>("请选择一个文件", HttpStatus.BAD_REQUEST);
        }

        try {
            Path uploadPath = Paths.get(UPLOAD_DIR);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }


            File targetFile = new File(uploadPath.toString(), file.getOriginalFilename());
            file.transferTo(targetFile);

            return new ResponseEntity<>("文件上传成功: " + file.getOriginalFilename(), HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity<>("文件上传失败：", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}
